﻿using System.Buffers.Binary;

namespace System;

/// <summary>
/// Provides extension methods for working with System.
/// </summary>
public static class ByteArrayExtension
{
    private static readonly char Space = ' ';

    /// <summary>
    /// Converts the byte array to a MemoryStream.
    /// </summary>
    /// <param name="byteArray">The byte array to convert.</param>
    /// <returns>The MemoryStream.</returns>
    public static MemoryStream ToMemoryStream(this byte[] byteArray)
    {
        if (byteArray == null)
        {
            throw new ArgumentNullException(nameof(byteArray));
        }

        return new MemoryStream(byteArray);
    }

    /// <summary>
    /// Converts the byte array to a hex string.
    /// </summary>
    /// <param name="bytes">The byte array to convert.</param>
    /// <returns>The hex string.</returns>
    public static string ToHexString(this byte[] bytes, bool spaceInterval = false)
    {
        if (bytes == null || bytes.Length == 0)
            return null;

        StringBuilder sb = new StringBuilder();
        int lastPos = bytes.Length - 1;
        for (int i = 0; i < bytes.Length; i++)
        {
            sb.Append(bytes[i].ToString("X2"));
            if (spaceInterval && i < lastPos)
                sb.Append(Space);
        }
        return sb.ToString();
    }

    public static string ToHexString(this Span<byte> bytes, bool spaceInterval = false)
    {
        if(bytes == null || bytes.Length == 0)
            return null;

        StringBuilder sb = new StringBuilder();
        int lastPos = bytes.Length - 1;
        for (int i = 0; i < bytes.Length; i++)
        {
            sb.Append(bytes[i].ToString("X2"));
            if (spaceInterval && i < lastPos)
                sb.Append(Space);
        }
        return sb.ToString();
    }

    public static short ToInt16(this Span<byte> bytes, bool isBigEndian = false)
    {
        if (isBigEndian)
            return BinaryPrimitives.ReadInt16BigEndian(bytes);
        return BinaryPrimitives.ReadInt16LittleEndian(bytes);
    }

    public static ushort ToUInt16(this Span<byte> bytes, bool isBigEndian = false)
    {
        if (isBigEndian)
            return BinaryPrimitives.ReadUInt16BigEndian(bytes);
        return BinaryPrimitives.ReadUInt16LittleEndian(bytes);
    }

    public static int ToInt32(this Span<byte> bytes, bool isBigEndian = false)
    {
        if (isBigEndian)
            return BinaryPrimitives.ReadInt32BigEndian(bytes);
        return BinaryPrimitives.ReadInt32LittleEndian(bytes);
    }

    public static uint ToUInt32(this Span<byte> bytes, bool isBigEndian = false)
    {
        if (isBigEndian)
            return BinaryPrimitives.ReadUInt32BigEndian(bytes);
        return BinaryPrimitives.ReadUInt32LittleEndian(bytes);
    }

    public static long ToInt64(this Span<byte> bytes, bool isBigEndian = false)
    {
        if (isBigEndian)
            return BinaryPrimitives.ReadInt64BigEndian(bytes);
        return BinaryPrimitives.ReadInt64LittleEndian(bytes);
    }

    public static ulong ToUInt64(this Span<byte> bytes, bool isBigEndian = false)
    {
        if (isBigEndian)
            return BinaryPrimitives.ReadUInt64BigEndian(bytes);
        return BinaryPrimitives.ReadUInt64LittleEndian(bytes);
    }

    /// <summary>
    /// 移除后面的0
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static Span<byte> TrimEnd(this Span<byte> data)
    {
        int len = data.Length;
        for (; len > 0; len--)
        {
            if (data[len - 1] > 0)
                break;
        }
        return data.Slice(0, len);
    }

    public static string ToBase64String(this byte[] bytes) => Convert.ToBase64String(bytes);

    public static string ToBase64String(this Span<byte> bytes) => Convert.ToBase64String(bytes);

    public static string ToUtf8String(this byte[] bytes) => Encoding.UTF8.GetString(bytes);

}